package com.yangcangclub.trade.service.impl;

import com.google.common.collect.Maps;
import com.yangcangclub.commons.exception.ApolloException;
import com.yangcangclub.commons.result.MessageEnum;
import com.yangcangclub.commons.utils.StringUtil;
import com.yangcangclub.trade.base.TradeBaseService;
import com.yangcangclub.trade.bean.*;
import com.yangcangclub.trade.service.TradeRefundService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
public class TradeRefundServiceImpl extends TradeBaseService implements TradeRefundService {

    private static Logger logger = LoggerFactory.getLogger(TradeRefundServiceImpl.class);

    /**退款申请（api）
     * @param userId
     * @param tradeId   订单id
     * @param refundType    退款类型
     * @param applyRefundPrice
     * @param applyRefundReasonType
     * @param applyRefundReason
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor= ApolloException.class)
    public boolean applyTradeRefund(int userId, int tradeId,int productId, String refundType,
                                                String applyRefundPrice, int applyRefundReasonType, String applyRefundReason) throws Exception {
        Map<String,Object> map = Maps.newHashMap();
        //查询订单是否存在
        TradeSummary tradeSummary = tradeDomain.selectTradeById(tradeId);
        if(tradeSummary==null){
            throw new ApolloException(MessageEnum.ERROR_TRADE_NOT_FOUND);
        }
        //如果是商品退，查看订单明细中是否存在，判断是否含有限购商品，存在则无法发起
        if("G".equals(refundType)){
            if(productId<=0){ throw new ApolloException(MessageEnum.PARMA_FORMAT_ERROR);}
            Map tradeDetailsMap = Maps.newHashMap();
            tradeDetailsMap.put("tradeNo",tradeSummary.getTradeNo());
            tradeDetailsMap.put("productId",productId);
            List<TradeDetails> tradeDetailsList = tradeDetailsDomain.selectPageBreakByCondition(tradeDetailsMap,1,10);
            if(tradeDetailsList.size()<=0){
                throw new ApolloException(MessageEnum.ERROR_TRADEREFUND_STATUS);
            }
            tradeDetailsMap.put("isLimit",2);
            List<TradeDetails> tradeDetailsIsLimitList = tradeDetailsDomain.selectPageBreakByCondition(tradeDetailsMap,1,10);
            if(tradeDetailsIsLimitList.size()>0){
                throw new ApolloException(MessageEnum.ERROR_TRADEREFUND_ISLIMIT);
            }
            if(new BigDecimal(applyRefundPrice).compareTo(tradeDetailsList.get(0).getProductTotalPrice())==1){
                throw new ApolloException(MessageEnum.ERROR_TRADEREFUND_PRICE);
            }
        }
        //如果是整单退，查看订单明细中是否存在，判断是否含有限购商品，存在则无法发起
        if("F".equals(refundType)){
            Map tradeDetailsMap = Maps.newHashMap();
            tradeDetailsMap.put("tradeNo",tradeSummary.getTradeNo());
            tradeDetailsMap.put("isLimit",2);
            List<TradeDetails> tradeDetailsIsLimitList = tradeDetailsDomain.selectPageBreakByCondition(tradeDetailsMap,1,10);
            if(tradeDetailsIsLimitList.size()>0){
                throw new ApolloException(MessageEnum.ERROR_TRADEREFUND_ISLIMIT);
            }
        }
        //比较退款金额与实付金额
        if(new BigDecimal(applyRefundPrice).compareTo(tradeSummary.getRealPrice())==1){
            throw new ApolloException(MessageEnum.ERROR_TRADEREFUND_PRICE);
        }
        //查询订单状态是否可退款，只有待发货D和已完成E才可以发起（是否干预 需要运营确定）
        if(!"D".equals(tradeSummary.getStatus()) && !"E".equals(tradeSummary.getStatus())){
            throw new ApolloException(MessageEnum.ERROR_TRADEREFUND_STATUS);
        }
        //判断是否有支付记录（有支付记录才能发起退款）
        Map tradeReqLogsMap = Maps.newHashMap();
        tradeReqLogsMap.put("tradeNo",tradeSummary.getTradeNo());
        tradeReqLogsMap.put("reqType",1);
        tradeReqLogsMap.put("resultStatus",0);
        List<TradeReqLogs> tradeReqLogsList = tradeReqLogsDomain.selectTradeReqLogsByCondition(tradeReqLogsMap);
        Map tradeResultLogsMap = Maps.newHashMap();
        tradeResultLogsMap.put("tradeNo",tradeSummary.getTradeNo());
        tradeResultLogsMap.put("resultType",1);
        List<TradeResultLogs> tradeResultLogsList = tradeResultLogsDomain.selectTradeResultLogsByCondition(tradeResultLogsMap);
        if(tradeReqLogsList.size()==0 || tradeResultLogsList.size()==0){
            throw new ApolloException(MessageEnum.ERROR_TRADEREFUND_NOPAYLOG);
        }
        //查询订单是否存在退款记录（根据订单号）
        List<TradeRefund> tradeRefundList = tradeRefundDomain.selectTradeRefundByTradeNo(tradeSummary.getTradeNo(),"manager");
        //存在
        if(tradeRefundList.size()>0){
            //判断退款类型是否为整单退，如果是整单退，则驳回（整单退款中或者存在部分退款，无法继续发起整单退）
            if("F".equals(refundType)){
                throw new ApolloException(MessageEnum.ERROR_TRADEREFUND_EXIST);
            }
            //如果退款类型不是整单退继续
            //判断退款商品是否发起过退款，存在记录则驳回
            Map tradeRefundMap = Maps.newHashMap();
            tradeRefundMap.put("tradeNo",tradeSummary.getTradeNo());
            tradeRefundMap.put("refundType","G");//G商品退款
            tradeRefundMap.put("userId",userId);
            int count = tradeRefundDomain.selectPageBreakByConditionCount(tradeRefundMap);
            if(count>0){
                throw new ApolloException(MessageEnum.ERROR_TRADEREFUND_PRODUCT_EXIST);
            }
            //退款商品不存在退款记录，则可正常退款申请
            // 增加退款记录
            TradeRefund tradeRefund = getTradeRefund(tradeSummary,productId, refundType,
                    applyRefundPrice, applyRefundReasonType, applyRefundReason);
            int tradeRefundId = tradeRefundDomain.insertTradeRefund(tradeRefund);
            //修改订单详细状态，修改订单状态（是否干预 需要运营确定）
            updateStatus(tradeId,userId,refundType,tradeSummary,productId);
        }else{
            //不存在
            // 增加退款记录
            TradeRefund tradeRefund = getTradeRefund(tradeSummary,productId, refundType,
                    applyRefundPrice, applyRefundReasonType, applyRefundReason);
            tradeRefundDomain.insertTradeRefund(tradeRefund);
            //修改订单详细状态，修改订单状态（是否干预 需要运营确定）
            updateStatus(tradeId,userId,refundType,tradeSummary,productId);
        }
        return true;
    }

    /** 获取退款列表（后台）
     * @param pageSize 每页大小
     * @param map      查询条件
     * @return
     * @throws Exception
     */
    @Override
    public Map<String, Object> applyTradeRefundList(int start, int pageSize, Map map) throws Exception {
        List<TradeRefundVo> tradeVoList = tradeRefundDomain.selectPageBreakByCondition(map,start,pageSize,"manager");
        int total = tradeRefundDomain.selectPageBreakByConditionCount(map);
        map.put("rows",tradeVoList);
        map.put("total",total);
        return map;
    }

    /**更新订单操作状态【目前仅支持[G待确认]状态】
     * @param auditId
     * @param auditName
     * @param tradeRefundId
     * @param status
     * @param remark
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor= ApolloException.class)
    public boolean updateTradeRefundOperationStatus(int auditId,String auditName, int tradeRefundId, String status, String remark) throws Exception {
        TradeRefund tradeRefund = tradeRefundDomain.selectTradeRefundById(tradeRefundId,"manager");
        if(tradeRefund==null){
            throw new ApolloException(MessageEnum.ERROR_TRADEREFUND_NOTFOUND);
        }
        //目前仅支持[G待确认]状态
        if(!"G".equals(tradeRefund.getRefundOperationStatus())){
            throw new ApolloException(MessageEnum.ERROR_TRADEREFUND_UPDATE);
        }
        //更新退款记录状态
        tradeRefund.setRefundOperationStatus(status);
        tradeRefund.setAuditDate(new Date());
        tradeRefund.setAuditUsername(auditName);
        tradeRefund.setAuditRemark(remark);
        tradeRefundDomain.updateTradeRefund(tradeRefund);
        //N退款失败，同步订单详细，同步订单
        if("N".equals(status)){
            //同步订单状态
            TradeSummary tradeSummary = tradeDomain.selectTradeByTradeNo(tradeRefund.getTradeNo());
            String remarkAppend = StringUtil.isNotEmpty(tradeSummary.getServiceRemark())?new StringBuffer(tradeSummary.getServiceRemark()).append(remark).toString():remark;
            tradeDomain.updateTradeStatus(tradeSummary.getId(),status,remarkAppend,auditId);
            //如果是F整单退款 更新订单详细的状态
            if("F".equals(tradeRefund.getRefundType())){
                tradeDetailsDomain.updateTradeDetailsStatusByTrandNo(tradeRefund.getTradeNo(),status);
            }
            //如果是G商品退款 更新订单详细的状态
            if("G".equals(tradeRefund.getRefundType())){
                tradeDetailsDomain.updateTradeDetailsStatusByTrandNoAndProductId(tradeRefund.getTradeNo(),tradeRefund.getRefundProductId(),status);
            }
        }
        return true;
    }

    /**发起退款
     * @param tradeRefundId
     * @param refundPrice
     * @param refundRemark
     * @param refundAccount
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor= ApolloException.class)
    public Map tradeRefund(int tradeRefundId, String refundPrice, String refundRemark,String refundAccount) throws Exception {
        TradeRefund tradeRefund = tradeRefundDomain.selectTradeRefundById(tradeRefundId,"manager");
        if(tradeRefund==null){
            throw new ApolloException(MessageEnum.ERROR_TRADEREFUND_NOTFOUND);
        }
        if(StringUtil.isEmpty(refundPrice)){
            throw new ApolloException(MessageEnum.PARMA_FORMAT_ERROR);
        }
        //目前仅支持[O已确认]状态
        if(!"O".equals(tradeRefund.getRefundOperationStatus())){
            throw new ApolloException(MessageEnum.ERROR_TRADEREFUND_UPDATE);
        }
        //判断支付方式，发起退款
        Map map = Maps.newHashMap();
        //微信公众号支付
        if(1==tradeRefund.getPayType()){
            if(!"REFUND_SOURCE_UNSETTLED_FUNDS".equals(refundAccount) && !"REFUND_SOURCE_RECHARGE_FUNDS".equals(refundAccount)){
                refundAccount = "";
            }
            map = weChatUtil.refund(tradeRefund.getTradeNo(),tradeRefund.getRefundNo(),refundAccount,tradeRefund.getRealPrice().toString(),refundPrice);
        }
        //支付宝web支付
        if(3==tradeRefund.getPayType()){
            map = alipayUtil.refund(tradeRefund.getTradeNo(),refundPrice,"退款",tradeRefund.getRefundNo());
        }
        //退款成功 更新退款记录状态、更新订单详细、更新主订单
        if(!map.isEmpty() && (boolean)map.get("result")){
            //更新退款记录状态
            tradeRefund.setRefundPrice(new BigDecimal(refundPrice));
            tradeRefund.setRefundDate(new Date());
            if(1==tradeRefund.getPayType()){
                tradeRefund.setRefundAccount(refundAccount);
            }
            tradeRefund.setRefundRemark(refundRemark);
            tradeRefund.setRefundOperationStatus("F");
            tradeRefundDomain.updateTradeRefund(tradeRefund);
            //更新订单详细
            //F整单退款
            if("F".equals(tradeRefund.getRefundType())){
                tradeDetailsDomain.updateTradeDetailsStatusByTrandNo(tradeRefund.getTradeNo(),"F");
            }
            //G商品退款
            if("G".equals(tradeRefund.getRefundType())){
                tradeDetailsDomain.updateTradeDetailsStatusByTrandNoAndProductId(tradeRefund.getTradeNo(),tradeRefund.getRefundProductId(),"F");
            }
            //更新主订单
            TradeSummary tradeSummary = tradeDomain.selectTradeByTradeNo(tradeRefund.getTradeNo());
            tradeDomain.updateTradeStatus(tradeSummary.getId(),"F","",0);
        }
        return map;
    }

    /**
     * @param tradeSummary
     * @param productId
     * @param refundType
     * @param applyRefundPrice
     * @param applyRefundReasonType
     * @param applyRefundReason
     * @return
     */
    private TradeRefund getTradeRefund(TradeSummary tradeSummary,int productId, String refundType,
                                       String applyRefundPrice, int applyRefundReasonType, String applyRefundReason){
        TradeRefund tradeRefund = new TradeRefund();
        tradeRefund.setUserId(tradeSummary.getUserId());
        tradeRefund.setTradeNo(tradeSummary.getTradeNo());
        tradeRefund.setRefundNo(identities.getRefundNo(tradeSummary.getUserId()));
        tradeRefund.setPayType(tradeSummary.getPayType());
        tradeRefund.setTransactionNo(tradeSummary.getTransactionNo());
        tradeRefund.setTransactionAccount(tradeSummary.getTransactionAccount());
        tradeRefund.setPayStatus(tradeSummary.getPayStatus());
        tradeRefund.setPayDate(tradeSummary.getPayDate());
        tradeRefund.setSource(tradeSummary.getSource());
        tradeRefund.setTradeTotalPrice(tradeSummary.getTradeTotalPrice());
        tradeRefund.setProductTotalPrice(tradeSummary.getProductTotalPrice());
        tradeRefund.setFreightPrice(tradeSummary.getFreightPrice());
        tradeRefund.setDiscountAmount(tradeSummary.getDiscountAmount());
        tradeRefund.setShouldPrice(tradeSummary.getShouldPrice());
        tradeRefund.setRealPrice(tradeSummary.getRealPrice());
        tradeRefund.setTradeStatus(tradeSummary.getStatus());
        tradeRefund.setApplyRefundPrice(new BigDecimal(applyRefundPrice));
        tradeRefund.setApplyRefundReasonType(applyRefundReasonType);
        tradeRefund.setApplyRefundReason(applyRefundReason);
        tradeRefund.setRefundType(refundType);
        //G商品退款
        if("G".equals(refundType)){
            tradeRefund.setRefundProductId(productId);
        }
        tradeRefund.setRefundOperationStatus("G");//退款状态（G待确认O已确认F已退款N退款失败）
        tradeRefund.setCreateDate(new Date());
        return tradeRefund;
    }

    /** 增加退款记录，修改订单详细状态，修改订单状态（是否干预 需要运营确定）
     * @param tradeId
     * @param userId
     * @param refundType
     * @param tradeSummary
     * @param productId
     */
    private void updateStatus(int tradeId,int userId,String refundType,TradeSummary tradeSummary,int productId){
        //修改订单详细状态
        if("G".equals(refundType)){
            tradeDetailsDomain.updateTradeDetailsStatusByTrandNoAndProductId(tradeSummary.getTradeNo(),productId,"G");
        }
        if("F".equals(refundType)){
            tradeDetailsDomain.updateTradeDetailsStatusByTrandNo(tradeSummary.getTradeNo(),"G");
        }
        //修改订单状态（是否干预 需要运营确定）
        tradeDomain.updateTradeStatus(tradeId,"G","",userId);
    }
    @Override
    public TradeVo getTradeVoByTradeNoAndTradeRefundId(int tradeRefundId, String tradeNo) throws Exception {
        return tradeDomain.selectTradeAllInfoByTradeNo(tradeRefundId,tradeNo);
    }
}
